/*
	Copyright (c) 2009-2011, Stefan Webb.

	This file is part of SimpleML. Please read the file "license.txt", 
	which contains the conditions under which this software is distributed.
*/

/*!
	\file console.h
	\author Stefan Webb
	\brief Definition of Console class
*/

#ifndef CONSOLE_H
#define CONSOLE_H

/*! \brief Specifies what type of output will be produced by the console.
	In the standard implementation it will change color, but you could,
	for example, redirect output to different windows of a GUI. */
enum ConsoleState
{
	/*! \brief Standard output. */
	STDOUT,

	/*! \brief Output of errors. */
	ERROUT,

	/*! \brief Output of warnings. This is separate from errors because you 
		may want them a different colour. */
	WARNOUT,

	/*! \brief Output of debug information. */
	DEBUGOUT
};

/*! \brief Specifies in which base to output numbers. */
enum RadixState
{
	/*! \brief Base 10. The default. */
	DECIMALBASE,

	/*! \brief Base 16. Useful for pointers etc. */
	HEXIDECIMAL,

	/*! \brief Base 2. Useful for integers containing flags. */
	BINARY
};

/*! \brief Class to interface with console. Firstly, replacing 
	standard library with this class reduces executable size.
	Secondly, you can modify/replace this class to redirect output. */
class Console : public HasState<ConsoleState>
// TODO: How can I use templates to do HasState<State1>, HasState<State2>??
{
public:
	/*! \brief Default constructor. */
	Console();

	/*! \brief Default destructor. */
	~Console();

	// TODO: What if this thread is not active? What if two threads are waiting for input?
	/*! \brief Pauses thread until a key is pressed. */
	void pressAnyKey();

	// TODO: Functions to get input from console.

	/*! \brief Set output radix for numbers.
		\param radix New desired radix.
		\return Console reference. */
	void setRadix(RadixState radix);

	/*! \brief Operator for setting radix. Makes it neater to chain operations.
		\param radix New desired radix.
		\return Console reference. */
	Console& operator<<(RadixState radix);

	/*! \brief Get current output radix for numbers.
		\return Current output radix for numbers. */
	RadixState getRadix();

	/*! \brief Operator for setting where console output is directed.
		\param destination New destination for console output.
		\return Console reference. */
	Console& operator<<(ConsoleState destination);

	/*! \brief Write UTF-8 string to console.
		\param string UTF-8 string to output.
		\return Console reference. */
	Console& operator<<(const utf8* string);
	
	/*! \brief Operator for writing UTF-16 string to console.
		\param string UTF-16 string to output.
		\return Console reference. */
	Console& operator<<(const utf16* string);

	/*! \brief Operator for writing signed byte to console.
		\param int8 Signed byte to output.
		\return Console reference. */
	Console& operator<<(const char int8);

	/*! \brief Operator for writing unsigned byte to console.
		\param uint8 Unsigned byte to output.
		\return Console reference. */
	Console& operator<<(const unsigned char uint8);

	/*! \brief Operator for writing signed word to console.
		\param int16 Signed word to output.
		\return Console reference. */
	Console& operator<<(const short int16);

	/*! \brief Operator for writing unsigned word to console.
		\param uint16 Unsigned word to output.
		\return Console reference. */
	Console& operator<<(const unsigned short uint16);

	/*! \brief Operator for writing signed integer to console.
		\param int32 Signed integer to output.
		\return Console reference. */
	Console& operator<<(const int int32);

	/*! \brief Operator for writing unsigned integer to console.
		\param uint32 Unsigned integer to output.
		\return Console reference. */
	Console& operator<<(const unsigned int uint32);

	// NOTE: By using long long we can make sure it's 64-bits on all compilers
	// TODO: Do I want to use int64, int32, uint32 etc. types which are defined in options header?
	/*! \brief Operator for writing signed long integer to console.
		\param uint64 Signed long integer to output.
		\return Console reference. */
	Console& operator<<(const long long int64);

	/*! \brief Operator for writing unsigned long integer to console.
		\param uint64 Unsigned long integer to output.
		\return Console reference. */
	Console& operator<<(const unsigned long long uint64);

	/*! \brief Operator for writing single precision floating number to console.
		\param number Single precision floating number to output.
		\return Console reference. */
	Console& operator<<(const float number);

	/*! \brief Operator for writing double precision floating number to console.
		\param number Double precision floating number to output.
		\return Console reference. */
	Console& operator<<(const double number);

	/*! \brief Operator for writing pointer address to console.
		\param pointer Pointer address to output.
		\return Console reference. */
	Console& operator<<(const void* pointer);

	/*! \brief Write UTF-8 string to console.
		\param string UTF-8 string to output. */
	void print(const utf8* string);

	/*! \brief Write UTF-16 string to console.
		\param string UTF-16 string to output. */
	void print(const utf16* string);

	/*! \brief Write signed byte to console.
		\param int8 Signed byte to output. */
	void print(const char int8);

	/*! \brief Write unsigned byte to console.
		\param uint8 Unsigned byte to output. */
	void print(const unsigned char uint8);

	/*! \brief Write signed word to console.
		\param int16 Signed word to output. */
	void print(const short int16);

	/*! \brief Write unsigned word to console.
		\param uint16 Unsigned word to output. */
	void print(const unsigned short uint16);

	/*! \brief Write signed integer to console.
		\param int32 Signed integer to output. */
	void print(const int int32);

	/*! \brief Write unsigned integer to console.
		\param uint32 Unsigned integer to output. */
	void print(const unsigned int uint32);

	/*! \brief Write signed long integer to console.
		\param uint64 Signed long integer to output. */
	void print(const long long int64);

	/*! \brief Write unsigned long integer to console.
		\param uint64 Unsigned long integer to output. */
	void print(const unsigned long long uint64);

	/*! \brief Write single precision floating number to console.
		\param number Single precision floating number to output. */
	void print(const float number);

	/*! \brief Write double precision floating number to console.
		\param number Double precision floating number to output. */
	void print(const double number);

	/*! \brief Write pointer address to console.
		\param pointer Pointer address to output. */
	void print(const void* pointer);

protected:
	/*! \brief Win32 handle for console output. */
	HANDLE hStdOut_;

	/*! \brief Win32 handle for console input. */
	HANDLE hStdIn_;

	// NOTE: Don't need this state because inherits from HasState class.
	/*! \brief Records to where the output will be redirected. */
	//ConsoleState destination_;

	/*! \brief Keeps record of what base we are outputting to. */
	RadixState radix_;

	/*! \brief Critical section to make console thread safe. This is because
		threads share memory for converting strings. */
	CriticalSection criticalSection_;
};

/*! \brief The global console object. */
extern Console console;	//wcout;

//#define wcin wcout

#define endl L"\n"

#endif